﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HR.ProjectX.DAL.UnitOfWork;
using HR.ProjectX.DAL.Repositories;
using HR.ProjectX.BLL.Messaging;
using HR.ProjectX.Models;
using HR.ProjectX.Models.Entities.Bookings;

namespace HR.ProjectX.BLL.Services.BookingService
{
    public class BookingService : IBookingService
    {
        private readonly IUnitOfWork _uow;
        private readonly IBookingRepository _bookingRepository;
        private readonly ICustomerRepository _customerRepository;
        private readonly IVehicleRepository _vehicleRepository;

        public BookingService(IUnitOfWork uow,
                              IBookingRepository bookingRepository,
                              ICustomerRepository customerRepository,
                              IVehicleRepository vehicleRepository)
        {
            _uow = uow;
            _bookingRepository = bookingRepository;
            _customerRepository = customerRepository;
            _vehicleRepository = vehicleRepository;
        }

        public void CreateBooking(CreateBookingRequest request)
        {
            Booking booking = new Booking();
            booking.BookingStatus = _bookingRepository.FindBookingStatusByDescription("Not Confirmed");
            booking.Customer = _customerRepository.FindCustomerByEmail(request.Email);
            booking.Vehicle = _vehicleRepository.FindVehicleByModel(request.VehicleModel);
            booking.DateFrom = Convert.ToDateTime(request.DateFrom);
            booking.DateTo = Convert.ToDateTime(request.DateTo);

            if (_customerRepository.FindCustomerByEmail(request.Email) == null)
            {
                throw new InvalidOperationException("There is no customer with this email address. Please register to become a customer.");
            }

            if (!_bookingRepository.IsBooked(request.VehicleModel, booking.DateFrom, booking.DateTo))
            {
                ThrowExceptionIfBookingIsInvalid(booking);

                _bookingRepository.Add(booking);
                _uow.Commit();
            }
            else
            {
                throw new InvalidOperationException("Already booked on this date.");
            }
        }

        private void ThrowExceptionIfBookingIsInvalid(Booking booking)
        {
            if (booking.GetBrokenRules().Count() > 0)
            {
                StringBuilder brokenRules = new StringBuilder();
                brokenRules.AppendLine("There were problems saving the Booking:");
                foreach (BusinessRule businessRule in booking.GetBrokenRules())
                {
                    brokenRules.AppendLine(businessRule.Rule);
                }

                throw new BookingInvalidException(brokenRules.ToString());
            }
        }
    }
}
